#!/usr/bin/perl
use strict;
use Getopt::Long;
use JNPR::Utils;

my $opts = {};
GetOptions ($opts, 'db=s', 'svnroot=s');
my ($S, $db);
if (!exists $opts->{'svnroot'}) {
    die "Error: $0 : need svnroot\n";
}
if (!exists $opts->{'db'}) {
    die "Error: $0 : need db\n";
}
$S = $opts->{'svnroot'};
$db = $opts->{db};

my $g_sql_out = [];
JNPR::Utils::set_url($S);
JNPR::Utils::mk_tables($db);




dig_remaining_versions_for_merges();


#
# --------------------------------------------------------------------
# --------------------------------------------------------------------
sub dig_remaining_versions_for_merges
{
    my ($merges_hi_rev, $merges_lo_rev)
           = JNPR::Utils::get_counts($db, 'merges_hi_rev', 'merges_lo_rev');

    if ($merges_hi_rev == -1 and $merges_lo_rev = -1) {
        my ($svn_hi_rev, $svn_lo_rev)
               = JNPR::Utils::get_counts($db, 'svn_hi_rev', 'svn_lo_rev');
        my ($done_hi, $done_lo) = (-1, -1);
        my $v = $svn_hi_rev;
        my $dig_success;
        while (1) {
            $dig_success = dig_version_for_merge($v);
            last if(!$dig_success);
            if ($done_hi == -1 or $done_hi < $v) {
                $done_hi = $v;
            }
            if ($done_lo == -1 or $v < $done_lo) {
                $done_lo = $v;
            }
            if (-e 'kill') {
                unlink 'kill';
                JNPR::Utils::set_counts($db, 'merges_hi_rev', $done_hi);
                JNPR::Utils::set_counts($db, 'merges_lo_rev', $done_lo);
                exit;
            }
            $v--;
        }
        JNPR::Utils::set_counts($db, 'merges_hi_rev', $done_hi);
        JNPR::Utils::set_counts($db, 'merges_lo_rev', $done_lo);
    }
    else {
        my $dig_success;
        # Downward
        {
            my $done_lo = $merges_lo_rev;;
            my $v = $merges_lo_rev - 1;
            while (1) {
                $dig_success = dig_version_for_merge($v);
                last if(!$dig_success);
                $done_lo = $v;
                if (-e 'kill') {
                    unlink 'kill';
                    JNPR::Utils::set_counts($db, 'merges_lo_rev', $done_lo);
                    exit;
                }
                $v--;
            }
            JNPR::Utils::set_counts($db, 'merges_lo_rev', $done_lo);
        }
        # Upward
        {
            my $done_hi = $merges_hi_rev;
            my $v = $merges_hi_rev + 1;
            while (1) {
                $dig_success = dig_version_for_merge($v);
                last if(!$dig_success);
                $done_hi = $v;
                if (-e 'kill') {
                    unlink 'kill';
                    JNPR::Utils::set_counts($db, 'merges_hi_rev', $done_hi);
                    exit;
                }
                $v++;
            }
            JNPR::Utils::set_counts($db, 'merges_hi_rev', $done_hi);
        }
    }
}


#
# --------------------------------------------------------------------
# --------------------------------------------------------------------
sub dig_version_for_merge
{
    my ($r) = @_;
    my $cmd;

    my ($d) = "00$r" =~ /(..)$/;

    my $rlog_file          = "$d/${r}-rlog.txt";
    my $old_mergeinfo_file = "$d/${r}-mergeinfo--.txt";
    my $new_mergeinfo_file = "$d/${r}-mergeinfo.txt";

    return 0 if (!-e $rlog_file);
    return 1 if (!-e $old_mergeinfo_file);
    return 1 if (!-e $new_mergeinfo_file);

    print "Doing: $new_mergeinfo_file\n";

    my  @old_mergeinfo = ();
    my  @new_mergeinfo = ();
    if (open F, "<$old_mergeinfo_file") {
        @old_mergeinfo = <F>;
        close F;
    }
    else {
        print "Cannot read $old_mergeinfo_file\n";
        return 1;
    }

    if (open F, "<$new_mergeinfo_file") {
        @new_mergeinfo = <F>;
        close F;
    }
    else {
        print "Cannot read $new_mergeinfo_file\n";
        return 1;
    }

    my $old_mergeinfo_hash = {};
    my $new_mergeinfo_hash = {};

    %{$old_mergeinfo_hash} = map {$_ => 1}
                             grep {$_ !~ /:$/}
                             map { simplify_mergeinfo($_) } @old_mergeinfo;
    # /branches/DEV_BORG_RLI11915_BRANCH:385757 => 1
    # /branches/DEV_CASHEW_Q4_BRANCH:386519 => 1
    # /branches/DEV_CBU_0810_BRANCH:380840 => 1
    # /branches/DEV_CBU_BROOKLYN40_2_BRANCH:410525 => 1
    # /branches/DEV_CBU_SHADOW_0211_BRANCH:418848 => 1
    # /branches/DEV_CBU_SHADOW_0810_BRANCH:385847 => 1
    # /branches/DEV_CBU_SHADOW_1110_BRANCH:397804 => 1
    # /branches/DEV_CBU_SHADOW_RLI_13292_BRANCH:414264 => 1
    # /branches/DEV_EX_1001_DOUBLECAP_BRANCH:395396 => 1
    # /branches/DEV_JBUILD_20100803_BRANCH:406836 => 1
    # ...
    %{$new_mergeinfo_hash} = map {$_ => 1}
                             grep {$_ !~ /:$/}
                             map { simplify_mergeinfo($_) } @new_mergeinfo;
    my @diffpl = ();
    for my $pl (keys %{$new_mergeinfo_hash}) {
        if (! exists $old_mergeinfo_hash->{$pl}) {
            push @diffpl, $pl;
        }
    }

    return 1 if (! scalar @diffpl);

    @diffpl = sort largest_rev_first @diffpl;

    my ($from_branch, $from_rev, $from_date) = get_revinfo($diffpl[0]);
    my ($to_branch,   $to_rev,   $to_date)   = get_revinfo($r);
    $cmd = "select merge_id from merges where from_rev = $from_rev and to_rev=$to_rev;\n";
    JNPR::Utils::sql_query($db, \$cmd, $g_sql_out);
    my $merge_id = $g_sql_out->[0];
    chomp $merge_id;
    return 1 if ($merge_id);

    $cmd = "INSERT INTO merges ( from_rev, to_rev ) VALUES ( $from_rev, $to_rev );\n";
    JNPR::Utils::sql_query($db, \$cmd, $g_sql_out);
    return 1;
}

#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub simplify_mergeinfo
{
    my $mergeinfo_line = shift;
    my $branchpath = '';
    my $revs;
    if ($_ =~ m{^(/branches/[^/]+):([\d\-\,\*]+)}) {
        ($branchpath, $revs) = ($1, $2);
    }
    elsif ($_ =~ m{^(/trunk):([\d\-\,\*]+)}) {
        ($branchpath, $revs) = ($1, $2);
    }
    my @lastrevs = $revs =~ m{\-(\d+)}g;
    @lastrevs = sort {$b <=> $a} @lastrevs;
    my $largest_rev = $lastrevs[0];
    return "$branchpath:$largest_rev";
}


#
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
sub largest_rev_first
{
    my ($aa) = $a =~ /(\d+)$/;
    my ($bb) = $b =~ /(\d+)$/;
    $bb <=> $aa;
}

#
# -------------------------------------------------------------------------
# Returns (branch, rev, date) or the revision
# -------------------------------------------------------------------------
sub get_revinfo
{
    my ($inputrev) = @_;
    # Could be any of these
    #   /branches/PR_BRANCH:449018
    #   /branches/PR_BRANCH@449018
    #   /trunk@449018
    #   /trunk:449018
    #   449018

    my $cmd;
    my ($branch, $rev, $date);
    if ($inputrev =~ m{([^/]+)[\:\@](\d+)$}) {
        ($branch, $rev) = ($1, $2);
        $cmd = "SELECT MAX(rev) FROM nodes WHERE branch = \"$branch\" AND rev <= $rev;\n";
        JNPR::Utils::sql_query($db, \$cmd, $g_sql_out);
        my $foundrev = $g_sql_out->[0];
        chomp $foundrev;
        if ($foundrev eq '') {     # The database does not know about this revision yet
                                   # We should look in subversion directly
            $cmd = "svn info $S/branches/$branch\@$rev 2>/dev/null";
            if ($branch eq 'trunk') {
                $cmd = "svn info $S/trunk\@$rev 2>/dev/null";
            }
            my @svninfo = `$cmd 2>/dev/null`;
            my %svninfo = map {chomp; /^([^\:]+?)\s*:\s*(.+)$/} @svninfo;
            # 'Repository UUID' => 'af97b9c9-8f30-47ec-ba46-ed83efb130c1',
            # 'URL' => 'https://svl-svn-01.juniper.net/svn/junos-2009/branches/PR_BRANCH',
            # 'Revision' => '564200',
            # 'Last Changed Date' => '2013-02-01 11:05:59 -0800 (Fri, 01 Feb 2013)',
            # 'Last Changed Rev' => '564191',
            # 'Path' => 'PR_BRANCH',
            # 'Last Changed Author' => 'mkopalle',
            # 'Repository Root' => 'https://svl-svn-01.juniper.net/svn/junos-2009',
            # 'Node Kind' => 'directory'


            if (scalar @svninfo == 0) { # This branch is probably too young. Did not exist in the
                                        # time of the revision.
                return ();
            }
            else {
                return ($branch, $svninfo{'Last Changed Rev'}, $svninfo{'Last Changed Date'});
            }
        }
        else {
            $rev = $foundrev;
        }
        chomp $rev;
    }
    elsif ($inputrev =~ /^\d+$/) {
        $rev = $inputrev;
    }

    $cmd = "SELECT branch, rev, date FROM nodes WHERE rev = $rev;\n";
    JNPR::Utils::sql_query($db, \$cmd, $g_sql_out);
    my $output = $g_sql_out->[0];
    chomp $output;
    return split /\|/, $output;
}

